using System;
using NUnit.Framework;
using dnA.Math;
using dnA.Exceptions;

namespace dnA.dnAtests.Math {
	[TestFixture]
	public class DoubleSVDDecompTest {
		private static DoubleSVDDecomp svd;
		private static DoubleSVDDecomp lsvd;
		private static DoubleSVDDecomp wsvd;
		private const double TOLERENCE = 0.001;

		static DoubleSVDDecompTest() {
			DoubleMatrix a = new DoubleMatrix(3);
			a[0,0] = 1.91;
			a[0,1] = 9.82;
			a[0,2] = 2.73;
			a[1,0] = 8.64;
			a[1,1] = 3.55;
			a[1,2] = 7.46;
			a[2,0] = 4.37;
			a[2,1] = 6.28;
			a[2,2] = 5.19;
			svd = new DoubleSVDDecomp(a);
			
			DoubleMatrix b = new DoubleMatrix(4,2);
			b[0,0] = 1.91;
			b[0,1] = 9.82;
			b[1,0] = 2.73;
			b[1,1] = 8.64;
			b[2,0] = 3.55;
			b[2,1] = 7.46;
			b[3,0] = 4.37;
			b[3,1] = 6.28;
			lsvd = new DoubleSVDDecomp(b);
				
			DoubleMatrix c = new DoubleMatrix(2,4);
			c[0,0] = 1.91;
			c[0,1] = 9.82;
			c[0,2] = 2.73;
			c[0,3] = 8.64;
			c[1,0] = 3.55;
			c[1,1] = 7.46;
			c[1,2] = 4.37;
			c[1,3] = 6.28;
			wsvd = new DoubleSVDDecomp(c);
		}

/*		[Test]
		public void UTest(){
			Assert.AreEqual(System.Math.Abs(svd.U[0,0]),0.526,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[0,1]),0.748,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[0,2]),0.405,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[1,0]),0.651,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[1,1]),0.660,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[1,2]),0.374,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[2,0]),0.547,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[2,1]),0.067,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.U[2,2]),0.834,TOLERENCE);
		}

		[Test]
		public void VTest(){
			Assert.AreEqual(System.Math.Abs(svd.V[0,0]),0.535,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[0,1]),0.554,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[0,2]),0.637,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[1,0]),0.648,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[1,1]),0.754,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[1,2]),0.111,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[2,0]),0.542,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[2,1]),0.353,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(svd.V[2,2]),0.763,TOLERENCE);
		}
*/
		[Test]
		public void STest(){
			DoubleMatrix s = svd.S;
			Assert.AreEqual(s[0,0],16.849,TOLERENCE);
			Assert.AreEqual(s[1,1],7.190,TOLERENCE);
			Assert.AreEqual(s[2,2],0.567,TOLERENCE);
		}

/*		[Test]
		public void LUTest(){
			Assert.AreEqual(System.Math.Abs(lsvd.U[0,0]),0.568,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[0,1]),0.614,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[1,0]),0.521,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[1,1]),0.170,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[2,0]),0.474,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[2,1]),0.275,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[3,0]),0.426,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.U[3,1]),0.720,TOLERENCE);
		}

		[Test]
		public void LVTest(){
			Assert.AreEqual(System.Math.Abs(lsvd.V[0,0]),0.348,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.V[0,1]),0.937,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.V[1,0]),0.937,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(lsvd.V[1,1]),0.348,TOLERENCE);
		}
*/
		[Test]
		public void LSTest(){
			Assert.AreEqual(lsvd.S.RowLength,2);
			Assert.AreEqual(lsvd.S.ColumnLength,2);
			Assert.AreEqual(lsvd.S[0,0],17.376,TOLERENCE);
			Assert.AreEqual(lsvd.S[1,1],2.653,TOLERENCE);
		}

/*		[Test]
		public void WUTest(){
			Assert.AreEqual(System.Math.Abs(wsvd.U[0,0]),0.770,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[0,1]),0.638,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[1,0]),0.638,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.U[1,1]),0.770,TOLERENCE);
		}

		[Test]
		public void WVTest(){
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,0]),0.214,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[0,1]),0.637,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,0]),0.707,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[1,1]),0.218,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,0]),0.281,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[2,1]),0.683,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,0]),0.612,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.V[3,1]),0.284,TOLERENCE);
		}
*/
		[Test]
		public void WSTest(){
			Assert.AreEqual(wsvd.S.RowLength,2);
			Assert.AreEqual(wsvd.S.ColumnLength,4);
			Assert.AreEqual(System.Math.Abs(wsvd.S[0,0]),17.416,TOLERENCE);
			Assert.AreEqual(System.Math.Abs(wsvd.S[1,1]),2.379,TOLERENCE);
		}

		[Test]
		public void RankTest(){
			Assert.AreEqual(svd.Rank,3);
		}		

		[Test]
		public void ConditionTest(){
			Assert.AreEqual(svd.Condition,29.701,TOLERENCE);
		}		

		[Test]
		public void NormTest(){
			Assert.AreEqual(svd.Norm2,16.849,TOLERENCE);
		}		
		
		[Test]
		public void LRankTest(){
			Assert.AreEqual(lsvd.Rank,2);
		}
		
		[Test]
		public void LConditionTest(){
			Assert.AreEqual(lsvd.Condition,6.551,TOLERENCE);
		}
		
		[Test]
		public void LNormTest(){
			Assert.AreEqual(lsvd.Norm2,17.376,TOLERENCE);
		}

		[Test]
		public void WRankTest(){
			Assert.AreEqual(wsvd.Rank,2);
		}
		
		[Test]
		public void WConditionTest(){
			Assert.AreEqual(wsvd.Condition,7.321,TOLERENCE);
		}
		
		[Test]
		public void WNormTest(){
			Assert.AreEqual(wsvd.Norm2,17.416,TOLERENCE);
		}
	}
}

